﻿//using ioman;
//using NuLib;
using System;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using IOLib;
using System.Collections.Generic;

namespace SheetLib
{
    public class BaseControl
    {
        private Color backColor;
        protected Brush blackBrush;
        private bool border;
        public Brush[] brush;
        protected Timer dblclick;
        //public Error errorId;
        private string errorText;
        private bool focused;
        protected System.Drawing.Font Font;
        private int fontHeight;
        private int hashInc;
        private static int HashInc;
        private bool inDate;
        private Point location;
        public bool needToDelete;
        protected Pen[] pen;
        private System.Drawing.Size PreviousSize;
        private bool selected;
        private Color selectedBackColor;
        private Color selectedTextColor;
        private System.Drawing.Size size;
        private Color textColor;
        public string uid;
        //protected Collection<UnReDO_Common> UnReDO;
        protected int UnReDoMaximum;
        protected int UnReDoPoint;
        private Color warningColor;
        protected List<Connector>[] associatedConnectors = new List<Connector>[] {
            new List<Connector>(), //right
            new List<Connector>(), //bottom
            new List<Connector>(), //left
            new List<Connector>() }; //top

        public delegate void ControlPaintEventHandler(BaseControl sender, Rectangle e);
        public delegate void ControlEventHandler(BaseControl sender);
        //public event CalculateAction CalculateMe;

        //public event NeedToDrawCustomLine drawCustomLine;

        //public event SMathDecision.ErrorProvider errorprovider;

        //public event HistoryChanged historyChanged;

        //public event CommonAction OnLinkClick;

        //public event CommonAction OnResize;
        public event ControlEventHandler OnResize;
        //public event ShowCalculationErrorEval onShowError;

        //public event ShowCalculationResultEval onShowResult;

        //public event RePaintMe repainting;
        public event ControlPaintEventHandler Repainting;
        //public event SetControlEvaluationState setControlEvaluationState;

        public BaseControl()
        {
            this.Init();
            this.border = false;
            this.size = new System.Drawing.Size(5, 5);
            //this.errorId = Error.NoError;
            this.ChangeFont(GlobalParams.fontsize_ISO);
            this.ChangeColors(GlobalParams.clr[0], GlobalParams.clr[2]);
        }

        public BaseControl(BaseControl value)
        {
            this.Init();
            this.border = value.border;
            this.size = value.size;
            //this.errorId = value.errorId;
            this.ChangeFont(value.FontHeight);
            this.ChangeColors(value.TextColor, value.BackColor);
        }

        public virtual void Action(string e)
        {
            if (e == "DELETE") this.needToDelete = true;
        }

        private void ChangeColors(Color textColor, Color backColor)
        {
            if (textColor.ToArgb() == SystemColors.WindowText.ToArgb())
            {
                this.textColor = SystemColors.WindowText;
            }
            else
            {
                this.textColor = textColor;
            }
            if (backColor.ToArgb() == SystemColors.Window.ToArgb())
            {
                this.backColor = SystemColors.Window;
            }
            else
            {
                this.backColor = backColor;
            }
            this.pen = new Pen[] { new Pen(this.textColor), new Pen(SystemColors.HighlightText) };//LangSelection.clr[1]) };
            this.brush = new SolidBrush[] { new SolidBrush(this.textColor), new SolidBrush(this.backColor), new SolidBrush(GlobalParams.clr[3]), new SolidBrush(GlobalParams.clr[1]), new SolidBrush(GlobalParams.clr[4]) };
        }

        private void ChangeFont(int value)
        {
            this.fontHeight = value;
            if (this.fontHeight < 1)
            {
                if (GlobalParams.fontsize_ISO < 1)
                {
                    GlobalParams.fontsize_ISO = 10;
                }
                this.fontHeight = GlobalParams.fontsize_ISO;
            }
            this.Font = new System.Drawing.Font("Courier New", (float) this.fontHeight, FontStyle.Regular);
        }

        private bool ChangeLocation(Point value)
        {
            if (this.location != value)
            {
                this.RePainter();
                this.location = value;
                this.RePainter();
                return true;
            }
            return false;
        }

        protected void CustomLineDrawing(PaintEventArgs e, Pen pen, int x1, int y1, int x2, int y2)
        {
            /*if (LangSelection.smoothGraphics && (this.drawCustomLine != null))
            {
                this.drawCustomLine(e, pen, e.ClipRectangle.X + x1, e.ClipRectangle.Y + y1, e.ClipRectangle.X + x2, e.ClipRectangle.Y + y2);
            }
            else*/
            {
                e.Graphics.DrawLine(pen, (int) (e.ClipRectangle.X + x1), (int) (e.ClipRectangle.Y + y1), (int) (e.ClipRectangle.X + x2), (int) (e.ClipRectangle.Y + y2));
            }
        }

        private void dblclick_Tick(object sender, EventArgs e)
        {
            this.dblclick.Enabled = false;
        }

        /*public void dec_errorprovider_nu(Exception e, int Position, EquImage value)
        {
            if (this.errorprovider != null)
            {
                this.errorprovider(e, Position, value, this);
            }
        }*/

        public void Focus()
        {
            this.Focused = true;
        }

        public virtual CursorType GetCursorType(MouseEventArgs point)
        {
            return CursorType.Arrow;
        }

        public override int GetHashCode()
        {
            return this.hashInc;
        }

        public Bitmap GetImage()
        {
            return this.GetImage(Color.White);
        }

        public Bitmap GetImage(Color bgColor)
        {
            bool focused = this.focused;
            if (focused)
            {
                this.focused = false;
            }
            this.PrePainter();
            Bitmap image = new Bitmap(this.Size.Width - 8, this.Size.Height - 8);
            Graphics graphics = Graphics.FromImage(image);
            graphics.Clear(bgColor);
            PaintEventArgs e = new PaintEventArgs(graphics, new Rectangle(0, 0, image.Width, image.Height));
            this.OnPaint(e);
            if (focused)
            {
                this.focused = true;
            }
            return image;
        }

        private void Init()
        {
            if ((HashInc + 1) == int.MaxValue)
            {
                HashInc = int.MinValue;
            }
            else
            {
                HashInc++;
            }
            this.hashInc = HashInc;
            this.UnReDoPoint = -1;
            this.UnReDoMaximum = -1;
            //this.UnReDO = new Collection<UnReDO_Common>();
            this.ErrorText = "";
            this.location = new Point(0, 0);
            this.PreviousSize = new System.Drawing.Size(5, 5);
            this.selected = false;
            this.focused = false;
            this.inDate = false;
            this.selectedTextColor = GlobalParams.clr[1];
            this.selectedBackColor = GlobalParams.clr[3];
            this.warningColor = GlobalParams.clr[4];
            this.blackBrush = new SolidBrush(Color.Black);
            this.dblclick = new Timer();
            this.dblclick.Enabled = false;
            this.dblclick.Interval = 300;
            this.dblclick.Tick += new EventHandler(this.dblclick_Tick);
        }

        public void LinkClick()
        {
            //if (this.OnLinkClick != null)
            //{
            //    this.OnLinkClick(this);
            //}
        }

        /*public void NeedToCalculate(CalculateType e, BaseControl sender)
        {
            if (this.CalculateMe != null)
            {
                this.CalculateMe(e, this);
            }
        }*/

        public virtual void OnMouseDown(MouseEventArgs e)
        {
        }

        public virtual void OnMouseMove(MouseEventArgs e)
        {
        }

        public virtual void OnMouseUp(MouseEventArgs e)
        {
        }

        public virtual void OnPaint(PaintEventArgs e)
        {
        }

        public virtual void PrePainter()
        {
            if (this.UnReDoPoint == -1)
            {
                this.UndoRedoManager();
            }
        }

        /*public UnReDO_Common ReDo()
        {
            if (((this.UnReDoPoint >= 0) && (this.UnReDO.Count > (this.UnReDoPoint + 1))) && (this.UnReDoMaximum > this.UnReDoPoint))
            {
                this.UnReDoPoint++;
                this.UnReDoAccept(this.UnReDO[this.UnReDoPoint]);
                return this.UnReDO[this.UnReDoPoint];
            }
            return null;
        }*/

        public void RePainter()
        {
            if (this.Repainting != null)
            {
                this.Repainting(this, new Rectangle(this.Location.X + 2, this.Location.Y + 2, ((this.Size.Width > this.PreviousSize.Width) ? this.Size.Width : this.PreviousSize.Width) - 4, ((this.Size.Height > this.PreviousSize.Height) ? this.Size.Height : this.PreviousSize.Height) - 4));
            }
            this.PreviousSize.Width = this.Size.Width;
            this.PreviousSize.Height = this.Size.Height;
        }

        protected virtual void Resize()
        {
            if ((this.PreviousSize.Width != this.Size.Width) || (this.PreviousSize.Height != this.Size.Height))
            {
                this.RePainter();
                if (this.OnResize != null)
                {
                    this.OnResize(this);
                }
            }
        }

        public void SetEvaluationState(bool state)
        {
            //if (this.setControlEvaluationState != null)
            //{
            //    this.setControlEvaluationState(this, state);
            //}
        }

        /*public void ShowError(Exception e, EquImage[] ei, ParamWizard param, CalculateType value)
        {
            if (this.onShowError != null)
            {
                this.onShowError(e, this, ei, param, value);
            }
        }*/

        /*public void ShowResult(EquImage[] ei, EquImage[] tstr2, CalculateType value)
        {
            if (this.onShowResult != null)
            {
                this.onShowResult(this, ei, tstr2, value);
            }
        }*/

        /*public UnReDO_Common UnDo()
        {
            if ((this.UnReDoPoint > 0) && (this.UnReDO.Count > this.UnReDoPoint))
            {
                this.UnReDoPoint--;
                this.UnReDoAccept(this.UnReDO[this.UnReDoPoint]);
                return this.UnReDO[this.UnReDoPoint];
            }
            return null;
        }*/

        protected virtual void UndoRedoManager()
        {
            ///this.UnReDoPush(new UnReDO_Common());
        }

        /*protected virtual void UnReDoAccept(UnReDO_Common unReDO_Common)
        {
            this.ChangeLocation(this.UnReDO[this.UnReDoPoint].Location);
            this.ChangeColors(this.UnReDO[this.UnReDoPoint].TextColor, this.UnReDO[this.UnReDoPoint].BackColor);
            this.ChangeFont(this.UnReDO[this.UnReDoPoint].FontHeight);
            this.PrePainter();
            this.RePainter();
        }*/

        /*protected void UnReDoPush(UnReDO_Common action)
        {
            action.Location = this.Location;
            action.TextColor = this.TextColor;
            action.BackColor = this.BackColor;
            action.FontHeight = this.FontHeight;
            if (this.UnReDoMaximum != this.UnReDoPoint)
            {
                this.UnReDO.RemoveRange(this.UnReDoPoint + 1, (this.UnReDO.Count - this.UnReDoPoint) - 1);
            }
            this.UnReDoPoint++;
            this.UnReDoMaximum = this.UnReDoPoint;
            this.UnReDO.Add(action);
            if ((this.UnReDoPoint > 0) && (this.historyChanged != null))
            {
                this.historyChanged(this);
            }
        }*/

        public virtual void UnReInit()
        {
            this.UnReDoPoint = -1;
        }

        public Color BackColor
        {
            get
            {
                return this.backColor;
            }
            set
            {
                if (this.backColor != value)
                {
                    this.backColor = value;
                    this.brush[1] = new SolidBrush(this.backColor);
                    this.UndoRedoManager();
                }
            }
        }

        public virtual bool Border
        {
            get
            {
                return this.border;
            }
            set
            {
                this.border = value;
            }
        }

        public int Bottom
        {
            get
            {
                return (this.Location.Y + this.Size.Height);
            }
        }

        public virtual string ErrorText
        {
            get
            {
                return this.errorText;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    //this.errorId = Error.NoError;
                }
                this.errorText = value;
            }
        }

        public virtual bool Focused
        {
            get
            {
                return this.focused;
            }
            set
            {
                this.focused = value;
            }
        }

        public int FontHeight
        {
            get
            {
                return this.fontHeight;
            }
            set
            {
                if (this.fontHeight != value)
                {
                    this.ChangeFont(value);
                    this.UndoRedoManager();
                }
            }
        }

        public virtual bool InDate
        {
            get
            {
                return this.inDate;
            }
            set
            {
                if (!value)
                {
                    this.ErrorText = "";
                }
                this.inDate = value;
            }
        }

        public Point Location
        {
            get
            {
                return this.location;
            }
            set
            {
                if (this.ChangeLocation(value))
                {
                    this.UndoRedoManager();
                }
            }
        }

        public int Right
        {
            get
            {
                return (this.Location.X + this.Size.Width);
            }
        }

        public bool Selected
        {
            get
            {
                return this.selected;
            }
            set
            {
                if (this.selected != value)
                {
                    this.selected = value;
                    this.RePainter();
                }
            }
        }

        public Color SelectedBackColor
        {
            get
            {
                return this.selectedBackColor;
            }
            set
            {
                if (this.selectedBackColor != value)
                {
                    this.selectedBackColor = value;
                }
            }
        }

        public Color SelectedTextColor
        {
            get
            {
                return this.selectedTextColor;
            }
            set
            {
                if (this.selectedTextColor != value)
                {
                    this.selectedTextColor = value;
                }
            }
        }

        public System.Drawing.Size Size
        {
            get
            {
                return this.size;
            }
            set
            {
                if (this.size != value)
                {
                    this.size = value;
                    this.Resize();
                }
            }
        }

        public Color TextColor
        {
            get
            {
                return this.textColor;
            }
            set
            {
                if (this.textColor != value)
                {
                    this.textColor = value;
                    this.pen[0] = new Pen(this.textColor);
                    this.brush[0] = new SolidBrush(this.textColor);
                    this.UndoRedoManager();
                }
            }
        }

        public Color WarningColor
        {
            get
            {
                return this.warningColor;
            }
            set
            {
                if (this.warningColor != value)
                {
                    this.warningColor = value;
                }
            }
        }

        public virtual Point GetConnectionPoint(ConnectionPlace connectionPlace)
        {
            switch (connectionPlace)
            {
                case ConnectionPlace.Right: return new Point(this.location.X + this.size.Width,
                    this.location.Y + this.size.Height / 2);
                case ConnectionPlace.Down: return new Point(this.location.X + this.size.Width/2,
                    this.location.Y + this.size.Height);
                case ConnectionPlace.Left: return new Point(this.location.X,
                    this.location.Y + this.size.Height / 2);
                case ConnectionPlace.Up: return new Point(this.location.X + this.size.Width/2,
                    this.location.Y);
                default: throw new ArgumentException();
            }
        }

        public virtual HotSpot[] GetConnHotSpots(bool start)
        {
            int radius = 4;
            HotSpot[] hss = new HotSpot[4];
            hss[0] = new HotSpot(this, new GraphicsPath(), ConnectionPlace.Right);
            hss[0].Area.AddEllipse(this.Right - radius, this.location.Y + this.size.Height / 2 - radius,
                2 * radius, 2 * radius);
            hss[1] = new HotSpot(this, new GraphicsPath(), ConnectionPlace.Down);
            hss[1].Area.AddEllipse(this.location.X + this.size.Width / 2 - radius, this.Bottom - radius,
                2 * radius, 2 * radius);
            hss[2] = new HotSpot(this, new GraphicsPath(), ConnectionPlace.Left);
            hss[2].Area.AddEllipse(this.location.X - radius, this.location.Y + this.size.Height / 2 - radius,
                2 * radius, 2 * radius);
            hss[3] = new HotSpot(this, new GraphicsPath(), ConnectionPlace.Up);
            hss[3].Area.AddEllipse(this.location.X + this.size.Width / 2 - radius, this.location.Y - radius,
                2 * radius, 2 * radius);
            return hss;
        }

        public virtual void AddAssociatedConnector(ConnectionPlace place, Connector c)
        {
            switch (place)
            {
                case ConnectionPlace.Right: this.associatedConnectors[0].Add(c); break;
                case ConnectionPlace.Down: this.associatedConnectors[1].Add(c); break;
                case ConnectionPlace.Left: this.associatedConnectors[2].Add(c); break;
                case ConnectionPlace.Up: this.associatedConnectors[3].Add(c); break;
            }
        }

        public List<Connector>[] AssociatedConnectors
        {
            get { return associatedConnectors; }
        }
    }

    public class HotSpot
    {
        public BaseControl Control;
        public GraphicsPath Area;
        public ConnectionPlace ConnectionPlace;

        public HotSpot(BaseControl Control, GraphicsPath Area, ConnectionPlace ConnectionPlace)
        {
            this.Control = Control;
            this.Area = Area;
            this.ConnectionPlace = ConnectionPlace;
        }

        public static bool operator ==(HotSpot hs1, HotSpot hs2)
        {
            if ((object.ReferenceEquals(hs1, null) && !object.ReferenceEquals(hs2, null)) ||
                (!object.ReferenceEquals(hs1, null) && object.ReferenceEquals(hs2, null)))
            {
                return false;
            }
            else if (object.ReferenceEquals(hs1, null) && object.ReferenceEquals(hs2, null))
            {
                return true;
            }
            else
            {
                return hs1.Control == hs2.Control && hs1.ConnectionPlace == hs2.ConnectionPlace;
            }
        }
        public static bool operator !=(HotSpot hs1, HotSpot hs2)
        {
            return !(hs1 == hs2);
        }
        public override bool Equals(object obj)
        {
            return obj is HotSpot && this == (HotSpot)obj;
        }
        public override int GetHashCode()
        {
            return Control.GetHashCode() ^ (int)ConnectionPlace;
        }
    }
}

